//
//  ViewFactory.m
//  
//
//  Created by frederic on 09/04/09.
//  Copyright 2009 FROM SCRATCH. All rights reserved.
//


#pragma mark -
#pragma mark UIImage+NSCoding
#pragma mark -

@interface UIImage (NSCoding)
- (id)initWithCoder:(NSCoder *)decoder;
- (void)encodeWithCoder:(NSCoder *)encoder;
@end

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

@implementation UIImage (NSCoding)
- (id)initWithCoder:(NSCoder *)decoder {
	NSData *pngData = [decoder decodeObjectForKey:@"PNGRepresentation"];
	[self autorelease];
	self = [[UIImage alloc] initWithData:pngData];
	return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
	[encoder encodeObject:UIImagePNGRepresentation(self) forKey:@"PNGRepresentation"];
}
@end

#import "ViewFactory.h"

#pragma mark -
#pragma mark ViewFactory
#pragma mark -

static ViewFactory *singleton = nil;

@interface ViewFactory(Private)

+ (ViewFactory*)_sharedSingleton;

- (void)_loadNib:(NSString*)aNibName;
- (UITableViewCell*)_cellOfKind: (NSString*)theCellKind forTable: (UITableView*)aTableView;
- (CGFloat)_heightForCellOfKind:(NSString*)theCellKind;
@end


@implementation ViewFactory

#pragma mark
#pragma mark - Singleton -

+(ViewFactory*)_sharedSingleton
{
	@synchronized(self)
	{
		if (!singleton)
			[[ViewFactory alloc] init];
		return singleton;
	}
	return nil;
}

+(id) alloc
{
	@synchronized(self)
	{
		NSAssert(singleton == nil, @"Attempted to allocate a second instance of a singleton.");
		singleton = [super alloc];
		return singleton;
	}
	return nil;
}

- (void) dealloc
{
    [viewTemplateStore release];
    [viewHeightStore release];
    [super dealloc];
}


- (id) init
{
    if (self == [super init]) {
        viewTemplateStore = [[NSMutableDictionary alloc] init] ;
        viewHeightStore = [[NSMutableDictionary alloc] init] ;
    }
    return self;
}	


#pragma mark
#pragma mark - Perform Load Nib -

- (void)_loadNib:(NSString*)aNibName
{
	NSArray * templates = [[NSBundle mainBundle] loadNibNamed:aNibName owner:self options:nil];
	for (id template in templates)
    {
		if ([template isKindOfClass:[UITableViewCell class]])
        {
			UITableViewCell * cellTemplate = (UITableViewCell *)template;
			NSString * key = cellTemplate.reuseIdentifier;
			
			if (key) {
				[viewTemplateStore setObject:[NSKeyedArchiver archivedDataWithRootObject:template]
									  forKey:key];

				[viewHeightStore setObject:[NSNumber numberWithFloat:cellTemplate.contentView.frame.size.height]
									forKey:key];
			} else {
				@throw [NSException exceptionWithName:@"Unknown cell"
											   reason:@"Cell has no reuseIdentifier"
											 userInfo:nil];
			}
		}
	}
}

+ (void) loadNib:(NSString*)aNibName {
	[[ViewFactory _sharedSingleton] _loadNib:aNibName];
}


#pragma mark
#pragma mark - View Builder -

+ (UIView*)viewFromNib:(NSString*)aNibName {
    
    NSArray * templates=nil;

    if ((aNibName != nil) && ([aNibName length] > 0)) {
        
        @try {
            templates =  [[NSBundle mainBundle] loadNibNamed:aNibName owner:self options:nil];
            //@throw [NSException exceptionWithName:@"Throwing a test exception" reason:@"Testing the @throw directive." userInfo:nil];
        }
        @catch (id theException) {
            NSLog(@"%@", theException);
        } 
        @finally {
            return (templates.count) ? [templates objectAtIndex:0] : nil;
        }
    }
    return nil;
}

+ (UIView*)viewFromNib:(NSString*)aNibName withTag:(NSInteger)tag {
    
    if ((aNibName != nil) && ([aNibName length] > 0)) {
        NSArray * templates = [[NSBundle mainBundle] loadNibNamed:aNibName owner:self options:nil];
        
        for (id object in templates) {
            if ([object isKindOfClass:[UIView class]] && ((UIView*)object).tag==tag)
                return object;
        }
    }
    return  nil;
}

+ (UIView*)viewFromNib:(NSString*)aNibName ofClass:(Class)aClass {
    
    if ((aNibName != nil) && ([aNibName length] > 0)) {
        NSArray * templates = [[NSBundle mainBundle] loadNibNamed:aNibName owner:self options:nil];
        
        for (id object in templates) {
            if ([object isKindOfClass:aClass])
                return object;
        }
    }
    return  nil;
}

#pragma mark
#pragma mark - Cell Store -z

- (UITableViewCell*)_cellOfKind:(NSString*)theCellKind forTable:(UITableView*)aTableView
{
    UITableViewCell *cell = nil;

	if (aTableView)
		cell = [aTableView dequeueReusableCellWithIdentifier:theCellKind];
	
    if (!cell) {
        NSData * cellData = [viewTemplateStore objectForKey:theCellKind];
        if (cellData) {
            cell = [NSKeyedUnarchiver unarchiveObjectWithData:cellData];
        } else {
            NSLog(@"Don't know nothing about cell of kind %@", theCellKind);
            cell = [[UITableViewCell new] autorelease];
        }
    }
    return cell;
}

+ (UITableViewCell*)cellOfKind:(NSString*)theCellKind forTable:(UITableView*)aTableView {
	return [[ViewFactory _sharedSingleton] _cellOfKind:theCellKind forTable:aTableView];
}

+ (UITableViewCell*)cellOfKind:(NSString*)theCellKind {
	return [[ViewFactory _sharedSingleton] _cellOfKind:theCellKind forTable:nil];
}


#pragma mark
#pragma mark - Height Store -

- (CGFloat)_heightForCellOfKind:(NSString*)theCellKind
{
	NSNumber *cellHeight = [viewHeightStore objectForKey:theCellKind];
	
	if (cellHeight) {
		return cellHeight.intValue;
    }
	
    return 0;
}

+ (CGFloat)heightForCellOfKind:(NSString*)theCellKind {
	return [[ViewFactory _sharedSingleton] _heightForCellOfKind:theCellKind];	
}

@end
